/**
 * 根据字段的语义类型进行可视化推荐
 * @author zhangfanfan
 */

import { ChartDetailsEnum } from '@/config/contant'
import { IColumn } from '@/store/modules/dataview'
import { uniq } from 'lodash'

interface DataField {
  id: string
  type: 'quantitative' | 'categorical' // TODO: ordinal, datetime
  semantic?: string
}

interface RecommendParameters {
  transformSetting?: [
    {
      transformMethod: 'precalculate' | 'geoTransform'
      transformConfig: {
        [any: string]: any
      }
    }
  ]
  chartSetting: {
    chartType: ChartDetailsEnum
    chartConfig: {
      groups: IColumn[]
      keys: IColumn[]
      values: IColumn[]
      [key: string]: any
    }
  }
}

const COLUMN_TYPE_NUMBER = new Set(['decimal', 'int']) // 字段类型：数值
const COLUMN_SEMANTIC_CATEGORY = new Set(['disorder', 'order']) // 语义类型：类别
// 语义和glyph type的对应
const GLYPH_TYPE: any = {
  country: 'world',
  province: 'country-province',
  city: 'country-city',
}

/**
 * 匹配一列情况的语义推荐规则
 */
function getSemanticParametersMatchOneColumn({
  geoArray = [],
  categoryArray = [],
  postCodeArray = [],
}: {
  geoArray?: IColumn[]
  categoryArray?: IColumn[]
  postCodeArray?: IColumn[]
}) {
  const result: RecommendParameters[] = []
  if (geoArray.length > 0) {
    // 1列IP地址、国家等出geomap + point
    geoArray.forEach((field: IColumn) => {
      const transformSetting: any = [
        {
          transformMethod: 'precalculate',
          transformConfig: {
            fields: [field],
            method: 'count',
          },
        },
      ]
      if (field.semantic !== 'coordinate') {
        transformSetting.push({
          transformMethod: 'geoTransform',
          transformConfig: {
            fields: [field],
          },
        })
      }
      result.push({
        // point glyph
        transformSetting,
        chartSetting: {
          chartType: ChartDetailsEnum.geographicMap,
          chartConfig: {
            groups: [],
            glyphConfig: {
              geoLayer: ['point'],
            },
            keys: [],
            values: [],
          },
        },
      })
      if (field.semantic && GLYPH_TYPE[field.semantic]) {
        result.push({
          // polygon glyph
          transformSetting: [
            {
              transformMethod: 'precalculate',
              transformConfig: {
                fields: [field],
                method: 'count',
              },
            },
          ],
          chartSetting: {
            chartType: ChartDetailsEnum.geographicMap,
            chartConfig: {
              groups: [],
              glyphConfig: {
                geoLayer: [GLYPH_TYPE[field.semantic]],
              },
              keys: [field],
              values: [],
            },
          },
        })
      }
    })
    //  [如果是城市或者省份语义，添加 地理bin barchart]
    if (['city', 'province'].includes(geoArray[0].semantic || '')) {
      result.push({
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: [
                {
                  ...geoArray[0],
                  binCount: 15,
                },
              ],
              method: 'count',
            },
          },
        ],
        chartSetting: {
          chartType: ChartDetailsEnum.barChart,
          chartConfig: {
            groups: [],
            keys: [
              {
                ...geoArray[0],
                name: `${geoArray[0].name}_after`,
              },
            ],
            values: [{ name: 'count', type: 0 }],
          },
        },
      })
    }
  }
  // 1列类别字段出barChart、pieChart
  if (categoryArray.length > 0) {
    categoryArray.forEach((field) => {
      result.push(
        {
          transformSetting: [
            {
              transformMethod: 'precalculate',
              transformConfig: {
                fields: [field],
                method: 'count',
              },
            },
          ],
          chartSetting: {
            chartType: ChartDetailsEnum.barChart,
            chartConfig: {
              groups: [],
              keys: [],
              values: [],
            },
          },
        },
        {
          transformSetting: [
            {
              transformMethod: 'precalculate',
              transformConfig: {
                fields: [field],
                method: 'count',
              },
            },
          ],
          chartSetting: {
            chartType: ChartDetailsEnum.pieChart,
            chartConfig: {
              groups: [],
              keys: [],
              values: [],
            },
          },
        }
      )
    })
  }
  //  for postcode: geomap point
  if (postCodeArray.length > 0) {
    postCodeArray.forEach((field: IColumn) => {
      const transformSetting: any = [
        {
          transformMethod: 'precalculate',
          transformConfig: {
            fields: [field],
            method: 'count',
          },
        },
      ]
      if (field.semantic !== 'coordinate') {
        transformSetting.push({
          transformMethod: 'geoTransform',
          transformConfig: {
            fields: [field],
          },
        })
      }
      result.push({
        // point glyph
        transformSetting,
        chartSetting: {
          chartType: ChartDetailsEnum.geographicMap,
          chartConfig: {
            groups: [],
            glyphConfig: {
              geoLayer: ['point'],
            },
            keys: [],
            values: [],
          },
        },
      })
    })
  }
  return result
}

/**
 * 匹配两列情况的语义推荐规则
 */
function getSemanticParametersMatchTwoColumn({
  geoArray,
  numberArray,
  categoryArray,
  dateArray,
}: {
  geoArray: IColumn[]
  categoryArray: IColumn[]
  // lngArray: IColumn[]
  numberArray: IColumn[]
  dateArray: IColumn[]
  // transformConfig: any
  // geoCombineField: string[][]
}) {
  const result: RecommendParameters[] = []
  if (geoArray.length === 1 && numberArray.length === 1) {
    // 地理语义 + 数值
    geoArray.forEach((geoField) => {
      numberArray.forEach((numberField) => {
        const transformSetting: any = [
          {
            transformMethod: 'precalculate', // 预计算是第一步，必须放在第一个
            transformConfig: {
              fields: [geoField],
              method: 'sum',
              targetField: numberField,
            },
          },
        ]
        if (geoField.semantic !== 'coordinate') {
          transformSetting.push({
            transformMethod: 'geoTransform',
            transformConfig: {
              fields: [geoField],
            },
          })
        }

        result.push({
          // point glyph
          transformSetting,
          chartSetting: {
            chartType: ChartDetailsEnum.geographicMap,
            chartConfig: {
              groups: [],
              glyphConfig: {
                geoLayer: ['point'],
                encodingType: 'area',
              },
              keys: [geoField],
              values: [numberField],
            },
          },
        })
        if (geoField.semantic && GLYPH_TYPE[geoField.semantic || '']) {
          result.push({
            // polygon glyph
            transformSetting: [transformSetting[0]],
            chartSetting: {
              chartType: ChartDetailsEnum.geographicMap,
              chartConfig: {
                groups: [],
                glyphConfig: {
                  geoLayer: [GLYPH_TYPE[geoField.semantic || '']],
                },
                keys: [geoField],
                values: [],
              },
            },
          })
        }
      })
    })
  }

  if (geoArray.length === 1 && categoryArray.length === 1) {
    // 地理坐标 + 类别
    const transformSetting: any = [
      {
        transformMethod: 'precalculate',
        transformConfig: {
          fields: geoArray.concat(categoryArray),
          method: 'count',
        },
      },
    ]
    if (geoArray[0].semantic !== 'coordinate') {
      // 非经纬度坐标需要做次转换，转成经纬度
      transformSetting.push({
        transformMethod: 'geoTransform',
        transformConfig: {
          fields: geoArray,
        },
      })
    }
    result.push(
      {
        transformSetting,
        chartSetting: {
          chartType: ChartDetailsEnum.stackBarChart,
          chartConfig: {
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            groups: [],
            keys: [],
            values: [],
            seriesField: categoryArray[0].name,
          },
        },
      },
      {
        // 多子图，pieChart、barChart
        transformSetting,
        chartSetting: {
          chartType: ChartDetailsEnum.geographicMap,
          chartConfig: {
            glyphConfig: {
              geoLayer: ['multi-subchart'],
              subChartType: 'barChart',
              encodingType: 'area',
            },
            groups: [],
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            keys: [],
            values: [],
          },
        },
      },
      {
        // 多子图，pieChart、barChart
        transformSetting,
        chartSetting: {
          chartType: ChartDetailsEnum.geographicMap,
          chartConfig: {
            glyphConfig: {
              geoLayer: ['multi-subchart'],
              subChartType: 'pieChart',
              encodingType: 'area',
            },
            groups: [],
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            keys: [],
            values: [],
          },
        },
      }
    )
  }

  if (geoArray.length === 2) {
    const transformSetting: any = [
      {
        transformMethod: 'precalculate',
        transformConfig: {
          fields: geoArray,
          method: 'count',
        },
      },
    ]
    const transformFields = geoArray.filter(
      (item) => item.semantic !== 'coordinate'
    )
    // 存在非坐标系的地理语义则需要转换，如省份、城市、ip等
    if (transformFields.length > 0) {
      transformSetting.push({
        transformMethod: 'geoTransform',
        transformConfig: {
          fields: transformFields,
        },
      })
    }

    result.push({
      transformSetting,
      chartSetting: {
        chartType: ChartDetailsEnum.geographicMap,
        chartConfig: {
          glyphConfig: {
            geoLayer: ['link'], // 多边形两个点的时候可画line
            // geoCombineField, // [[经度id，纬度id，合成的经纬度id]]单独的经度和维度字段，经度在前
          },
          groups: [],
          keys: geoArray,
          values: [],
        },
      },
    })
  }
  if (geoArray.length === 1 && dateArray.length === 1) {
    // 地理语义 + 时间
    const transformSetting: any = [
      {
        transformMethod: 'precalculate',
        transformConfig: {
          fields: geoArray.concat(dateArray),
          method: 'count',
        },
      },
    ]
    if (geoArray[0].semantic !== 'coordinate') {
      // 非经纬度坐标需要做次转换，转成经纬度
      transformSetting.push({
        transformMethod: 'geoTransform',
        transformConfig: {
          fields: geoArray,
        },
      })
    }
    result.push({
      // 多子图，pieChart、barChart
      transformSetting,
      chartSetting: {
        chartType: ChartDetailsEnum.geographicMap,
        chartConfig: {
          glyphConfig: {
            geoLayer: ['multi-subchart'],
            subChartType: 'donutChart',
            encodingType: 'area',
          },
          groups: [],
          // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
          keys: [],
          values: [],
        },
      },
    })
  }

  return result
}

/**
 * 匹配三列情况的语义推荐规则
 */
function getSemanticParametersMatchThreeColumn({
  geoArray,
  numberArray,
  categoryArray,
  dateArray,
}: {
  geoArray: IColumn[]
  categoryArray: IColumn[]
  // lngArray: IColumn[]
  numberArray: IColumn[]
  dateArray: IColumn[]
}) {
  const result: RecommendParameters[] = []
  // 经纬度*2 +数值
  if (geoArray.length === 2 && numberArray.length === 1) {
    const transformSetting: any = [
      {
        transformMethod: 'precalculate',
        transformConfig: {
          fields: geoArray,
          method: 'avg',
          targetField: numberArray[0],
        },
      },
    ]
    const transformFields = geoArray.filter(
      (item) => item.semantic !== 'coordinate'
    )
    // 存在非坐标系的地理语义则需要转换，如省份、城市、ip等
    if (transformFields.length > 0) {
      transformSetting.push({
        transformMethod: 'geoTransform',
        transformConfig: {
          fields: transformFields,
        },
      })
    }

    result.push({
      transformSetting,
      chartSetting: {
        chartType: ChartDetailsEnum.geographicMap,
        chartConfig: {
          glyphConfig: {
            geoLayer: ['link'],
            // geoCombineField, // [[经度id，纬度id，合成的经纬度id]]单独的经度和维度字段，经度在前
          },
          groups: [],
          keys: geoArray,
          values: numberArray,
        },
      },
    })
  }

  // 经纬度+类别+数值
  if (
    geoArray.length === 1 &&
    categoryArray.length >= 1 && //  number 可能也是category
    numberArray.length === 1
  ) {
    const transformSetting: any = [
      {
        transformMethod: 'precalculate',
        transformConfig: {
          fields: geoArray.concat(categoryArray),
          method: 'avg',
          targetField: numberArray[0],
        },
      },
    ]
    if (geoArray[0].semantic !== 'coordinate') {
      // 非经纬度坐标需要做次转换，转成经纬度
      transformSetting.push({
        transformMethod: 'geoTransform',
        transformConfig: {
          fields: geoArray,
        },
      })
    }
    result.push(
      {
        // 多子图，pieChart、barChart
        transformSetting,
        chartSetting: {
          chartType: ChartDetailsEnum.geographicMap,
          chartConfig: {
            glyphConfig: {
              geoLayer: ['multi-subchart'],
              subChartType: 'donutChart',
            },
            groups: [],
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            keys: [],
            values: [],
          },
        },
      },
      {
        // 多子图，pieChart、barChart
        transformSetting,
        chartSetting: {
          chartType: ChartDetailsEnum.geographicMap,
          chartConfig: {
            glyphConfig: {
              geoLayer: ['multi-subchart'],
              subChartType: 'barChart',
            },
            groups: [],
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            keys: [],
            values: [],
          },
        },
      },
      //  stackBarChart
      {
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: geoArray.concat(categoryArray),
              method: 'sum',
              targetField: numberArray[0],
            },
          },
        ],
        chartSetting: {
          chartType: ChartDetailsEnum.stackBarChart,
          chartConfig: {
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            groups: [],
            keys: [],
            values: [],
            seriesField: categoryArray[0].name,
          },
        },
      }
    )
  }

  // 经纬度+时间+数值
  if (
    geoArray.length === 1 &&
    dateArray.length === 1 &&
    numberArray.length === 1
  ) {
    const transformSetting: any = [
      {
        transformMethod: 'precalculate',
        transformConfig: {
          fields: geoArray.concat(dateArray),
          method: 'avg',
          targetField: numberArray[0],
        },
      },
    ]
    if (geoArray[0].semantic !== 'coordinate') {
      // 非经纬度坐标需要做次转换，转成经纬度
      transformSetting.push({
        transformMethod: 'geoTransform',
        transformConfig: {
          fields: geoArray,
        },
      })
    }
    result.push({
      // 多子图，pieChart、barChart
      transformSetting,
      chartSetting: {
        chartType: ChartDetailsEnum.geographicMap,
        chartConfig: {
          glyphConfig: {
            geoLayer: ['multi-subchart'],
            subChartType: 'pieChart',
          },
          groups: [],
          // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
          keys: [],
          values: [],
        },
      },
    })
  }
  return result
}

/**
 * 获取地理语义的可视化推荐参数
 * @param usedFields 选中的字段
 * @param allFields 全部字段
 * @param targetCount 目标要匹配的规则列数 目前范围是1-3(在没有匹配的情况下，筛选的列中取子集列，看看是否匹配，所以设定匹配列数)
 */
function getGeoRecommendParameters(
  usedFields: IColumn[],
  allFields: IColumn[],
  targetCount: number
): RecommendParameters[] {
  if (usedFields.length === 0) {
    usedFields = allFields
  }
  const geoArray = usedFields.filter((item) =>
    ['coordinate', 'ip', 'country', 'province', 'city'].includes(
      item.semantic || ''
    )
  ) // 经纬度
  //  邮编，仅有单列的时候才出图，所有单独处理
  const postCodeArray = usedFields.filter((item) =>
    ['postcode'].includes(item.semantic || '')
  )
  // const countryArray = usedFields.filter(
  //   (item) => (item.semantic || '') === 'country'
  // ) // 国家名字段
  const latArray = usedFields.filter((item) =>
    ['latitude'].includes(item.semantic || '')
  ) // 单独纬度字段
  const lngArray = usedFields.filter((item) =>
    ['longitude'].includes(item.semantic || '')
  ) // 单独经度字段
  const nonGeoArray = usedFields.filter(
    (item) =>
      ![
        'coordinate',
        'ip',
        'country',
        'province',
        'city',
        'latitude',
        'longitude',
      ].includes(item.semantic || '')
  ) // 非地理语义字段
  const numberArray = nonGeoArray.filter((item) =>
    COLUMN_TYPE_NUMBER.has(item.desc ?? '')
  ) // 数值字段

  // 日期/时间字段
  const dateArray = usedFields.filter((item) => item.desc === 'date')
  // 类别语义字段
  const categoryArray = nonGeoArray.filter((item) =>
    COLUMN_SEMANTIC_CATEGORY.has(item.semantic ?? '')
  )

  // const numberCount = numberArray.length
  const geoArrayCount = geoArray.length
  const latArrayCount = latArray.length
  const lngArrayCount = lngArray.length

  if (
    postCodeArray.length === 0 &&
    (latArrayCount !== lngArrayCount ||
      (latArrayCount === 0 && geoArrayCount === 0))
  ) {
    // 无有效的坐标点
    return []
  }
  let result: RecommendParameters[] = []
  // 先临时注释掉 by zhangfanfan 2021-08-23
  // const geoCount = latArrayCount + geoArrayCount
  // const transformFields = geoArray.filter(
  //   (item) => item.semantic !== 'coordinate'
  // )
  // const needTransform = transformFields.length > 0 // 存在非坐标系的地理语义则需要转换，如省份、城市、ip等
  // let transformConfig = {}
  // if (needTransform) {
  //   transformConfig = {
  //     transformSetting: {
  //       transformMethod: 'geoTransform',
  //       transformConfig: {
  //         fields: transformFields,
  //       },
  //     },
  //   }
  // }
  const geoCombineField: string[][] = []
  if (latArrayCount > 0) {
    // 存在单独的纬度字段，则需和单独经度字段一一匹配成组
    latArray.forEach((item, index) => {
      geoCombineField.push([
        lngArray[index].name,
        item.name,
        `$$${lngArray[index].name}-${item.name}-${index}$$`,
      ])
    })
  }

  // targetCount 匹配规则中的列个数
  switch (targetCount) {
    case 1:
      result = [
        ...result,
        ...getSemanticParametersMatchOneColumn({ geoArray, postCodeArray }),
      ]
      break
    case 2:
      result = [
        ...result,
        ...getSemanticParametersMatchTwoColumn({
          geoArray,
          numberArray,
          categoryArray,
          dateArray,
        }),
      ]
      break
    case 3:
      result = [
        ...result,
        ...getSemanticParametersMatchThreeColumn({
          geoArray,
          numberArray,
          categoryArray,
          dateArray,
        }),
      ]
      break
    default:
      break
  }

  return result
}

/**
 * 获取非地理语义的可视化推荐参数
 * @param usedFields 选中的字段
 * @param allFields 全部字段
 * @param targetCount 目标要匹配的规则列数 目前范围是1-3(在没有匹配的情况下，筛选的列中取子集列，看看是否匹配，所以设定匹配列数)
 * @returns
 */
function getNonGeoSemanticParameters(
  usedFields: IColumn[],
  allFields: IColumn[],
  targetCount: number
): RecommendParameters[] {
  // 类别语义字段
  const categoryArray = usedFields.filter((item) =>
    COLUMN_SEMANTIC_CATEGORY.has(item.semantic ?? '')
  )
  // targetCount 匹配规则中的列个数
  let result: RecommendParameters[] = []
  switch (targetCount) {
    case 1:
      result = [
        ...result,
        ...getSemanticParametersMatchOneColumn({ categoryArray }),
      ]
      break
    // case 2:
    //   result = [
    //     ...result,
    //     ...getSemanticParametersMatchTwoColumn({
    //       categoryArray,
    //     }),
    //   ]
    //   break
    default:
      break
  }

  return result
}

/**
 * 根据字段语义进行可视化推荐
 * @param usedFields 已选字段
 * @param allFields 数据表所有字段
 */
export function getRecommendParametersBySemantic(
  usedFields: IColumn[],
  allFields: IColumn[],
  targetCount: number
): RecommendParameters[] | [] {
  const result: RecommendParameters[] = [
    // 获取地理语义的可视化推荐参数，语义中最重的一部分，单独拿出来
    ...getGeoRecommendParameters(usedFields, allFields, targetCount),
    ...getNonGeoSemanticParameters(usedFields, allFields, targetCount),
  ]
  return result
}

/**
 * 根据数据列类型合成推荐参数，只匹配一列的规则
 * @param param0 numberArray dateArray
 * @returns 推荐参数
 */
function getTypeParametersMatchOneColumn({
  numberArray,
  dateArray,
}: {
  numberArray: IColumn[]
  dateArray: IColumn[]
}) {
  const result: RecommendParameters[] = []
  if (numberArray.length > 0) {
    numberArray.forEach((numberField) => {
      result.push({
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: [
                {
                  ...numberField,
                  binCount: 15,
                },
              ],
              method: 'count',
            },
          },
        ],
        chartSetting: {
          chartType: ChartDetailsEnum.barChart,
          chartConfig: {
            groups: [],
            keys: [
              {
                ...numberField,
                name: `${numberField.name}_after`,
              },
            ],
            values: [{ name: 'count', type: 0 }], // Todo type
          },
        },
      })
    })
  } else if (dateArray.length > 0) {
    result.push({
      transformSetting: [
        {
          transformMethod: 'precalculate',
          transformConfig: {
            fields: [
              {
                ...dateArray[0],
                binCount: 15,
              },
            ],
            method: 'count',
          },
        },
      ],
      chartSetting: {
        chartType: ChartDetailsEnum.barChart,
        chartConfig: {
          groups: [],
          keys: [
            {
              ...dateArray[0],
              name: `${dateArray[0].name}_after`,
            },
          ],
          values: [{ name: 'count', type: 0 }],
        },
      },
    })
  }
  return result
}

/**
 * 根据数据列类型合成推荐参数，只匹配两列的规则
 * @param param0 numberArray
 * @returns 推荐参数
 */
function getTypeParametersMatchTwoColumn({
  numberArray,
  categoryArray,
  stringArray,
  dateArray,
}: {
  numberArray: IColumn[]
  categoryArray: IColumn[]
  stringArray: IColumn[]
  dateArray: IColumn[]
}) {
  const result: RecommendParameters[] = []
  const target = uniq([...categoryArray, ...stringArray])
  if (numberArray.length === 2) {
    result.push(
      {
        // 1对1的散点图
        chartSetting: {
          chartType: ChartDetailsEnum.scatterplot,
          chartConfig: {
            groups: [],
            keys: [numberArray[0]],
            values: [numberArray[1]],
          },
        },
      },
      //  binCount scatter
      {
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: [
                {
                  ...numberArray[0],
                  binCount: 10,
                },
                {
                  ...numberArray[1],
                  binCount: 10,
                },
              ], //  count
              method: 'count',
            },
          },
        ],
        //  TBD 用点的大小来编码count个数
        chartSetting: {
          chartType: ChartDetailsEnum.scatterplot,
          chartConfig: {
            groups: [],
            keys: [],
            values: [],
            sizeField: 'count',
            pointRadius: [5, 10],
          },
        },
      },
      {
        // 一列做bin，另一类算区间count
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: [
                {
                  ...numberArray[0],
                  binCount: 10,
                },
              ],
              method: 'count',
              targetField: numberArray[1],
            },
          },
        ],
        chartSetting: {
          chartType: ChartDetailsEnum.barChart,
          chartConfig: {
            groups: [],
            keys: [
              {
                ...numberArray[0],
                name: `${numberArray[0].name}_after`,
              },
            ],
            values: [numberArray[1]],
          },
        },
      },
      {
        // 一列做bin，另一类算区间avg
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: [
                {
                  ...numberArray[0],
                  binCount: 10,
                },
              ],
              method: 'avg',
              targetField: numberArray[1],
            },
          },
        ],
        chartSetting: {
          chartType: ChartDetailsEnum.barChart,
          chartConfig: {
            groups: [],
            keys: [
              {
                ...numberArray[0],
                name: `${numberArray[0].name}_after`,
              },
            ],
            values: [numberArray[1]],
          },
        },
      }
    )
  } else if (numberArray.length === 1) {
    //  number length = 1
    if (target.length > 0) {
      result.push(
        //  类别唯一  TBD
        // {
        //   chartSetting: {
        //     chartType: ChartDetailsEnum.barChart,
        //     chartConfig: {
        //       groups: [],
        //       keys: [target[0]],
        //       values: [numberArray[0]],
        //     },
        //   },
        // },
        //  类别不唯一  TBD
        {
          chartSetting: {
            chartType: ChartDetailsEnum.scatterplot,
            chartConfig: {
              groups: [],
              keys: [numberArray[0]],
              values: [target[0]],
            },
          },
        },
        {
          transformSetting: [
            {
              transformMethod: 'precalculate',
              transformConfig: {
                fields: [target[0]],
                method: 'avg',
                targetField: numberArray[0],
              },
            },
          ],
          chartSetting: {
            chartType: ChartDetailsEnum.barChart,
            chartConfig: {
              groups: [],
              keys: [],
              values: [],
            },
          },
        },
        {
          transformSetting: [
            {
              transformMethod: 'precalculate',
              transformConfig: {
                fields: [target[0]],
                method: 'avg',
                targetField: numberArray[0],
              },
            },
          ],
          chartSetting: {
            chartType: ChartDetailsEnum.pieChart,
            chartConfig: {
              groups: [],
              keys: [],
              values: [],
            },
          },
        }
      )
    }

    if (dateArray.length === 1) {
      const transformSetting: any = [
        {
          transformMethod: 'precalculate',
          transformConfig: {
            fields: dateArray,
            method: 'sum',
            targetField: numberArray[0],
          },
        },
      ]
      //  linechart, areachart
      result.push(
        {
          // 默认同一个时间有多个数值，需要做聚合计算
          transformSetting,
          chartSetting: {
            chartType: ChartDetailsEnum.lineChart,
            chartConfig: {
              groups: [],
              keys: dateArray,
              values: numberArray,
            },
          },
        },
        {
          transformSetting,
          chartSetting: {
            chartType: ChartDetailsEnum.areaChart,
            chartConfig: {
              groups: [],
              keys: dateArray,
              values: numberArray,
            },
          },
        }
      )
    }
  } else if (target.length === 2) {
    //  类别/字符串*2

    //  stackedBarChart (count的维度两个都分别画)
    target.forEach((field, index) => {
      result.push({
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: [field, index === 0 ? target[1] : target[0]],
              method: 'count',
              // targetField: index === 0 ? target[1] : target[0],
            },
          },
        ],
        chartSetting: {
          chartType: ChartDetailsEnum.stackBarChart,
          chartConfig: {
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            groups: [],
            keys: [],
            values: [],
            seriesField: index === 0 ? target[1].name : target[0].name,
          },
        },
      })
    })

    //  groupedBarChart
    result.push(
      {
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: [target[0], target[1]],
              method: 'count',
              // targetField: target[1],
            },
          },
        ],
        chartSetting: {
          chartType: ChartDetailsEnum.groupBarChart,
          chartConfig: {
            // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
            groups: [],
            keys: [],
            values: [],
            seriesField: target[1].name,
          },
        },
      },
      {
        transformSetting: [
          {
            transformMethod: 'precalculate',
            transformConfig: {
              fields: target, //  count
              method: 'count',
            },
          },
        ],
        //  TBD 用点的大小来编码count个数
        chartSetting: {
          chartType: ChartDetailsEnum.scatterplot,
          chartConfig: {
            groups: [],
            keys: [],
            values: [],
            sizeField: 'count',
            pointRadius: [5, 10],
          },
        },
      }
      // {
      //   //  normal scatterplot 唯一的情况
      //   chartSetting: {
      //     chartType: ChartDetailsEnum.scatterplot,
      //     chartConfig: {
      //       groups: [],
      //       keys: [target[0]],
      //       values: [target[1]],
      //     },
      //   },
      // }
    )

    //  heatmap matrix
    result.push({
      transformSetting: [
        {
          transformMethod: 'precalculate',
          transformConfig: {
            fields: target,
            method: 'count',
          },
        },
      ],
      chartSetting: {
        chartType: ChartDetailsEnum.heatmapMatrix,
        chartConfig: {
          // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
          groups: [],
          keys: [],
          values: [],
          heatMapDataKey: 'count',
        },
      },
    })
  } else if (dateArray.length === 1) {
    //  case1: category/string
    if (target.length === 1) {
      result.push(
        {
          transformSetting: [
            {
              transformMethod: 'precalculate',
              transformConfig: {
                fields: [dateArray[0], target[0]],
                method: 'count',
                // targetField: target[0],
              },
            },
          ],
          chartSetting: {
            chartType: ChartDetailsEnum.groupBarChart, //  groupBarChart
            chartConfig: {
              groups: [],
              keys: [],
              values: [],
              seriesField: target[0].name,
            },
          },
        },
        {
          transformSetting: [
            {
              transformMethod: 'precalculate',
              transformConfig: {
                fields: [dateArray[0], target[0]],
                method: 'count',
                // targetField: target[0],
              },
            },
          ],
          chartSetting: {
            chartType: ChartDetailsEnum.stackBarChart, //  groupBarChart
            chartConfig: {
              groups: [],
              keys: [],
              values: [],
              seriesField: target[0].name,
            },
          },
        }
        // {
        //   transformSetting: [
        //     {
        //       transformMethod: 'precalculate',
        //       transformConfig: {
        //         fields: [
        //           {
        //             ...dateArray[0],
        //             binCount: 10,
        //           },
        //           {
        //             ...target[0],
        //           },
        //         ],
        //         method: 'count',
        //         // targetField: target[0],
        //       },
        //     },
        //   ],
        //   chartSetting: {
        //     chartType: ChartDetailsEnum.groupBarChart, //  groupBarChart
        //     chartConfig: {
        //       groups: [],
        //       keys: [],
        //       values: [],
        //       seriesField: target[0].name,
        //     },
        //   },
        // }
      )
    }
  }
  return result
}

/**
 * 根据数据列类型(+ 类别语义字段)合成推荐参数，只匹配三列的规则
 * @param param0 numberArray
 * @returns 推荐参数
 */
function getTypeParametersMatchThreeColumn({
  numberArray,
  categoryArray,
  stringArray,
  dateArray,
}: {
  numberArray: IColumn[]
  categoryArray: IColumn[]
  stringArray: IColumn[]
  dateArray: IColumn[]
}) {
  const result: RecommendParameters[] = []
  const target = uniq([...categoryArray, ...stringArray])

  if (numberArray.length === 3) {
    // 数值 + 数值 + 数值
    const indexMapping = [
      [1, 2],
      [0, 2],
      [0, 1],
    ]
    numberArray.forEach((numberField, index) => {
      result.push({
        // 依次选2列做1对1的散点图，第3列进行着色
        chartSetting: {
          chartType: ChartDetailsEnum.scatterplot,
          chartConfig: {
            groups: [],
            keys: [numberArray[indexMapping[index][0]]],
            values: [numberArray[indexMapping[index][1]]],
            colorField: numberField.name,
          },
        },
      })
    })
  }
  // 类别/字符串 + 数值 + 数值
  if (numberArray.length === 2 && target.length === 1) {
    const colorField = target[0].name
    // categoryArray.length === 1 ? categoryArray[0].name : stringArray[0].name
    result.push({
      chartSetting: {
        chartType: ChartDetailsEnum.scatterplot,
        chartConfig: {
          groups: [],
          keys: [numberArray[0]],
          values: [numberArray[1]],
          colorField,
        },
      },
    })
  }

  // 类别/字符串 + 类别/字符串 + 数值
  if (numberArray.length === 1 && target.length === 2) {
    //  有可能即时字符串又是类别
    target.forEach((field, index) => {
      result.push(
        {
          chartSetting: {
            chartType: ChartDetailsEnum.scatterplot,
            chartConfig: {
              groups: [],
              keys: [numberArray[0]],
              values: [field],
              colorField: index === 0 ? target[1].name : target[0].name,
            },
          },
        }
        // {
        //   chartSetting: {
        //     chartType: ChartDetailsEnum.heatmapMatrix,
        //     chartConfig: {
        //       // 有precalculate的 keys、values的值从 precalculate 接口的返回值取
        //       groups: [],
        //       keys: [target[0]],
        //       values: [target[1]],
        //       heatMapDataKey: numberArray[0].name,
        //     },
        //   },
        // }
      )
    })
  }
  // 类别/字符串+时间+数值
  if (
    dateArray.length === 1 &&
    numberArray.length === 1 &&
    target.length === 1
  ) {
    target.forEach((field) => {
      result.push({
        chartSetting: {
          chartType: ChartDetailsEnum.lineChart,
          chartConfig: {
            groups: [],
            keys: dateArray,
            values: numberArray,
            seriesField: field.name,
          },
        },
      })
    })
  }
  return result
}

/**
 * 根据字段类型进行可视化推荐
 * @param usedFields 已选字段
 * @param allFields 数据表所有字段
 * @param targetCount 目标匹配列的个数，目前规则最多到3
 * @returns
 */
export function getRecommendParametersByType(
  usedFields: IColumn[],
  allFields: IColumn[],
  targetCount: number
): RecommendParameters[] | [] {
  // 数值字段
  const numberArray = usedFields.filter((item) =>
    COLUMN_TYPE_NUMBER.has(item.desc ?? '')
  )
  // 类别语义字段
  const categoryArray = usedFields.filter((item) =>
    COLUMN_SEMANTIC_CATEGORY.has(item.semantic ?? '')
  )
  // 字符串类型字段
  const stringArray = usedFields.filter((item) => item.desc === 'varchar')
  // 日期类型字段
  const dateArray = usedFields.filter((item) => item.desc === 'date')

  let result: RecommendParameters[] = []
  switch (
    targetCount // 最多3列
  ) {
    case 1: // 匹配规则：一列
      result = [
        ...result,
        ...getTypeParametersMatchOneColumn({ numberArray, dateArray }),
      ]
      break
    case 2: // 匹配规则：两列
      result = [
        ...result,
        ...getTypeParametersMatchTwoColumn({
          numberArray,
          categoryArray,
          stringArray,
          dateArray,
        }),
      ]
      break
    case 3:
      result = [
        ...result,
        ...getTypeParametersMatchThreeColumn({
          numberArray,
          categoryArray,
          stringArray,
          dateArray,
        }),
      ]
      break
    default:
      break
  }
  return result
}
